package cn.iocoder.yudao.module.book.service.app;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.book.controller.app.vo.*;
import cn.iocoder.yudao.module.book.dal.dataobject.BookCheckInRecordDO;
import cn.iocoder.yudao.module.book.dal.dataobject.book.BookDO;
import cn.iocoder.yudao.module.book.dal.dataobject.record.RecordDO;
import cn.iocoder.yudao.module.book.dal.mysql.BookCheckInRecordMapper;
import cn.iocoder.yudao.module.book.dal.mysql.record.RecordMapper;
import cn.iocoder.yudao.module.book.service.admin.book.BookService;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import jakarta.annotation.Resource;

@Service
public class AppBookCheckInRecordServiceImpl implements AppBookCheckInRecordService {

    @Resource
    private BookCheckInRecordMapper bookCheckInRecordMapper;
    @Resource
    private RecordMapper bookRecordMapper;
    @Resource
    private BookService bookService;
    @Resource
    private AdminUserService adminUserService;

    @Override
    public Long createBookCheckInRecord(AppBookCheckInRecordSaveReqVO bookCheckInRecordSaveReqVO) {
        if (!checkInValidation()) {
            throw new ServiceException(9999, "当天需阅读至少1本绘本才能打卡");
        }
        // 用户当天可多次进入打卡页面，所有后续打卡均为对第一次打卡的更新
        LambdaQueryWrapper<BookCheckInRecordDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BookCheckInRecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.eq(BookCheckInRecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.ge(BookCheckInRecordDO::getCreateTime, LocalDate.now().atStartOfDay());
        queryWrapper.le(BookCheckInRecordDO::getCreateTime, LocalDate.now().atTime(23, 59, 59, 999));

        Optional<BookCheckInRecordDO> bookCheckInRecordDO = Optional.ofNullable(bookCheckInRecordMapper.selectOne(queryWrapper));
        BookCheckInRecordDO recordDO = bookCheckInRecordDO.orElseGet(BookCheckInRecordDO::new);
        recordDO.setReadingNotes(bookCheckInRecordSaveReqVO.getReadingNotes());
        recordDO.setUserId(SecurityFrameworkUtils.getLoginUserId());
        recordDO.setBookIds(getDayRecordBooks());

        if (bookCheckInRecordDO.isEmpty()) {
            bookCheckInRecordMapper.insert(recordDO);
        } else {
            bookCheckInRecordMapper.updateById(recordDO);
        }
        return recordDO.getId();
    }

    private String getDayRecordBooks() {
        LambdaQueryWrapper<RecordDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.ge(RecordDO::getCreateTime, LocalDate.now().atStartOfDay());
        queryWrapper.le(RecordDO::getCreateTime, LocalDate.now().atTime(23, 59, 59, 999));
        List<RecordDO> list = bookRecordMapper.selectList(queryWrapper);
        return list.stream().map(RecordDO::getBookId).map(String::valueOf).collect(Collectors.joining("_"));
    }

    @Override
    public Boolean checkInValidation() {
        LambdaQueryWrapper<RecordDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.ge(RecordDO::getCreateTime, LocalDate.now().atStartOfDay());
        queryWrapper.le(RecordDO::getCreateTime, LocalDate.now().atTime(23, 59, 59, 999));
        Long count = bookRecordMapper.selectCount(queryWrapper);
        return count != 0;
    }

    @Override
    public AppCheckInCalendarDataRespVO getCheckInCalendarData() {
        AppCheckInCalendarDataRespVO checkInCalendarDataRespVO = new AppCheckInCalendarDataRespVO();
        LocalDate today = LocalDate.now();
        LocalDateTime monthStart = today.with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
        LocalDateTime monthEnd = today.with(TemporalAdjusters.lastDayOfMonth()).atTime(23, 59, 59, 999);
        // 查询本月打卡记录
        LambdaQueryWrapper<BookCheckInRecordDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BookCheckInRecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        queryWrapper.between(BookCheckInRecordDO::getCreateTime, monthStart, monthEnd);
        List<BookCheckInRecordDO> records = bookCheckInRecordMapper.selectList(queryWrapper);
        checkInCalendarDataRespVO.setCheckinDays(records.size());
        checkInCalendarDataRespVO.setContinuousDays(records.size());
        if (CollUtil.isNotEmpty(records)) {
            List<Integer> dayList = records.stream().map(BookCheckInRecordDO::getCreateTime).map(LocalDateTime::getDayOfMonth).toList();
            checkInCalendarDataRespVO.setCurrentMonthCheckInDates(dayList);
        }
        // 查询上个月打卡记录
        LambdaQueryWrapper<BookCheckInRecordDO> lastQueryWrapper = new LambdaQueryWrapper<>();
        lastQueryWrapper.eq(BookCheckInRecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        LocalDateTime lastMonthStart = today.minusMonths(1).with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay();
        LocalDateTime lastMonthEnd = today.minusMonths(1).with(TemporalAdjusters.lastDayOfMonth()).atTime(23, 59, 59, 999);
        lastQueryWrapper.between(BookCheckInRecordDO::getCreateTime, lastMonthStart, lastMonthEnd);
        List<BookCheckInRecordDO> lastRecords = bookCheckInRecordMapper.selectList(lastQueryWrapper);
        checkInCalendarDataRespVO.setLastCheckinDays(lastRecords.size());
        if (CollUtil.isNotEmpty(lastRecords)) {
            List<Integer> lastDayList = lastRecords.stream().map(BookCheckInRecordDO::getCreateTime).map(LocalDateTime::getDayOfMonth).toList();
            checkInCalendarDataRespVO.setLastMonthCheckInDates(lastDayList);
        }
        return checkInCalendarDataRespVO;
    }

    @Override
    public List<AppAllUsersRecentCheckInRecordsRespVO> allUsersRecentCheckInRecords(String currentTab) {
        switch (currentTab) {
            case "latest", "follow":
                return bookCheckInRecordMapper.allUsersRecentCheckInRecords();
            case "mine":
                return bookCheckInRecordMapper.myUsersRecentCheckInRecords(String.valueOf(SecurityFrameworkUtils.getLoginUserId()));
            default:
                return null;
        }
    }

    @Override
    public AppBookCheckInRecordSaveRespVO getBookCheckInRecordById() {
        AppBookCheckInRecordSaveRespVO bookCheckInRecordSaveRespVO = new AppBookCheckInRecordSaveRespVO();
        // 设置今日阅读量
        bookCheckInRecordSaveRespVO.setTodayReadingTotal(bookRecordMapper.countTodayRecords());
        // 设置本周阅读量
        bookCheckInRecordSaveRespVO.setThisWeekReadingTotal(bookRecordMapper.countThisWeekRecords());
        // 设置本月阅读量
        bookCheckInRecordSaveRespVO.setThisMonthReadingTotal(bookRecordMapper.countThisMonthRecords());
        // 设置总阅读量
        bookCheckInRecordSaveRespVO.setTotalNumberOfReadings(bookRecordMapper.countAllRecords());
        // 查询 createTime 最早的记录
        RecordDO earliestRecord = bookRecordMapper.selectEarliestRecord();
        // 获取 createTime
        LocalDateTime createTime = earliestRecord.getCreateTime();
        // 计算已阅读的天数
        long daysSinceCreation = ChronoUnit.DAYS.between(createTime, LocalDateTime.now());
        bookCheckInRecordSaveRespVO.setReadingDays((int)daysSinceCreation);
        // 设置打卡天数
        LambdaQueryWrapper<BookCheckInRecordDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BookCheckInRecordDO::getUserId, SecurityFrameworkUtils.getLoginUserId());
        bookCheckInRecordSaveRespVO.setCheckInDays(bookCheckInRecordMapper.selectCount(queryWrapper));

        List<BookCheckInRecordDO> bookCheckInRecordDOList = bookCheckInRecordMapper.selectList();
        List<AppBookCheckInRecordListVO> bookCheckInRecordListVOList = BeanUtils.toBean(bookCheckInRecordDOList, AppBookCheckInRecordListVO.class);
        bookCheckInRecordListVOList.forEach(item -> {
            String[] bookIds = item.getBookIds().split("_");
            List<BookDO> bookDOList = new ArrayList<>();
            for (String bookId : bookIds) {
                BookDO bookDO = bookService.getBook(Long.valueOf(bookId));
                if (bookDO != null) {
                    bookDOList.add(bookDO);
                }
                item.setBookDOList(bookDOList);
            }
            AdminUserDO adminUserDO = adminUserService.getUser(Long.valueOf(item.getCreator()));
            if (adminUserDO != null) {
                item.setCreateName(adminUserDO.getNickname());
            }
        });
        return bookCheckInRecordSaveRespVO;
    }
}